package com.spyx.activity.service.impl;

import com.atyx.spyx.enums.ActivityType;
import com.atyx.spyx.model.activity.ActivityInfo;
import com.atyx.spyx.model.activity.ActivityRule;
import com.atyx.spyx.model.activity.ActivitySku;
import com.atyx.spyx.model.activity.CouponInfo;
import com.atyx.spyx.model.order.CartInfo;
import com.atyx.spyx.model.product.SkuInfo;
import com.atyx.spyx.vo.activity.ActivityRuleVo;
import com.atyx.spyx.vo.order.CartInfoVo;
import com.atyx.spyx.vo.order.OrderConfirmVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.spyx.activity.mapper.ActivityInfoMapper;
import com.spyx.activity.mapper.ActivityRuleMapper;
import com.spyx.activity.mapper.ActivitySkuMapper;
import com.spyx.activity.service.ActivityInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.spyx.activity.service.CouponInfoService;
import com.spyx.product.ProductClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 活动表 服务实现类
 * </p>
 *
 * @author yhp
 * @since 2024-05-21
 */
@Service
public class ActivityInfoServiceImpl extends ServiceImpl<ActivityInfoMapper, ActivityInfo> implements ActivityInfoService {

    @Override
    public IPage<ActivityInfo> selectPage(Page p1) {

        IPage<ActivityInfo> pagemodel = baseMapper.selectPage(p1, null);
        //由于ActivityInfo中的activityType这一列的类型是枚举值，需要取出数据后再做处理
        List<ActivityInfo> infoList = pagemodel.getRecords();
        for (ActivityInfo info : infoList) {
            info.setActivityTypeString(info.getActivityType().getComment());
        }
        return pagemodel;
    }


    @Autowired
    private ActivityRuleMapper activityRuleMapper;
    @Autowired
    private ActivitySkuMapper activitySkuMapper;

    @Autowired
    private ProductClient productClient;

    @Override
    public Map<String, Object> findActivityRuleListByActivityId(Integer activityId) {
        //1.创建Map集合，用来封装结果
        Map map=new HashMap();
        //2.根据activityId，查询activity_rule表
        LambdaQueryWrapper<ActivityRule> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ActivityRule::getActivityId,activityId);
        List<ActivityRule> activityRuleList = activityRuleMapper.selectList(wrapper);
        map.put("activityRuleList",activityRuleList);
        //3.根据activityId,查询activity_sku表
        LambdaQueryWrapper<ActivitySku> queryWrapper = new LambdaQueryWrapper<ActivitySku>();
        queryWrapper.eq(ActivitySku::getActivityId,activityId);
        //返回的数据中只有skuid,没有商品的其他信息
        List<ActivitySku> activitySkuList = activitySkuMapper.selectList(queryWrapper);
        if(!CollectionUtils.isEmpty(activitySkuList)){
            //4.提取activitySkuList中的所有的skuId,远程调用service-product服务，实现根据ids查询skuInfo信息
            List<Long> skuIdList =
                    activitySkuList.stream().map(ActivitySku::getSkuId).collect(Collectors.toList());
            //5.调取远程服务,查询skuInfoList
            List<SkuInfo> skuInfoList = productClient.getskuInfoListbyids(skuIdList);
            map.put("skuInfoList",skuInfoList);
        }
        //TODO 查询couponInfoList

        return map;
    }

    @Override
    public void saveRule(ActivityRuleVo activityRuleVo) {
        //由于不确定前端是对规则增加了还是减少了，所以需要先删除原有的规则和商品列表，再新增
        Long activityId = activityRuleVo.getActivityId();
        //1.根据获取活动ID删除原来的规则-activity_rule
        LambdaQueryWrapper<ActivityRule> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ActivityRule::getActivityId,activityId);
        activityRuleMapper.delete(wrapper);
        //2.根据获取的活动id,删除原来的activity_sku列表
        LambdaQueryWrapper<ActivitySku> wrapper2 = new LambdaQueryWrapper<>();
        wrapper2.eq(ActivitySku::getActivityId,activityId);
        activitySkuMapper.delete(wrapper2);
        //3.给activity_rule表中新增数据
        List<ActivityRule> activityRuleList = activityRuleVo.getActivityRuleList();
        //3.1 根据活动id,查询活动的类型值
        ActivityInfo activityInfo = baseMapper.selectById(activityId);
        for (ActivityRule activityRule : activityRuleList) {
             activityRule.setActivityId(activityId);
             activityRule.setActivityType(activityInfo.getActivityType());//设置活动类型-需要根据前端发送的活动iD,查询activity_info表的活动类型这一列
             activityRuleMapper.insert(activityRule);
        }
        //4.添加activity_sku表的数据
        List<ActivitySku> activitySkuList = activityRuleVo.getActivitySkuList();
        for (ActivitySku activitySku : activitySkuList) {
            activitySku.setActivityId(activityId);
            activitySkuMapper.insert(activitySku);
        }
        //TODO  新增优惠券的列表数据

    }

    @Override
    public List<SkuInfo> getSkuInfoList(String keyword) {
        //当前所在位置是操作Activity_info表，但是当前方法要查询:根据关键字模糊查询sku_info表(shequ-product)
        //解决方法:远程调用
        //1.根据关键字查询出相关的skuinfo列表(参加活动+没有参加活动的商品列表)
        List<SkuInfo> skuInfoList = productClient.getSkuInfoListBykeyword(keyword);
        //2.查询哪些商品参加了活动？？-需要手动编写sql语句
        //2.1 先将参加和没参加过活动的商品id值提取出来
        List<Long> idList = skuInfoList.stream().map(SkuInfo::getId).collect(Collectors.toList());
        //2.2 将所有检索出来的id值传递给sql,进行查询
        // 将参加了某个时间段的商品的id检索出来
        List<Long> ids= baseMapper.selectInActityIds(idList);

        //3.创建一个集合，保存未参加活动的商品列表
        List<SkuInfo> notInSkuInfoList=new ArrayList<>();
        for (SkuInfo skuInfo : skuInfoList) {
            if(!ids.contains(skuInfo.getId())){
                notInSkuInfoList.add(skuInfo);
            }
        }

        return notInSkuInfoList;
    }

    @Override
    public Map<Long, List<String>> findActivity(List<Long> skuidList) {
        //1.创建一个Map集合封装最后的结果
        Map<Long, List<String>> map=new HashMap();
        //2.遍历每件商品的skuid,根据这个id,查询该商品所对应的活动规则
        for (Long skuid : skuidList) {
            List<ActivityRule> activityRuleList= baseMapper.selectActivityRuleList(skuid);
            //2.1 判断规则列表是否有值
            if(!CollectionUtils.isEmpty(activityRuleList)){
                 List<String> ruleStringList=new ArrayList<String>(); //将activityRule规则信息转换成string,保存到集合中
                for (ActivityRule activityRule : activityRuleList) {
                     //将活动规则转换成字符串
                    String ruleDesc = this.getRuleDesc(activityRule);
                    ruleStringList.add(ruleDesc);
                }
                //封装结果
                map.put(skuid,ruleStringList);
            }
        }
        return map;
    }


    //直接复制即可
    private String getRuleDesc(ActivityRule activityRule) {
        ActivityType activityType = activityRule.getActivityType();
        StringBuffer ruleDesc = new StringBuffer();
        if (activityType == ActivityType.FULL_REDUCTION) {
            ruleDesc
                    .append("满")
                    .append(activityRule.getConditionAmount())
                    .append("元减")
                    .append(activityRule.getBenefitAmount())
                    .append("元");
        } else {
            ruleDesc
                    .append("满")
                    .append(activityRule.getConditionNum())
                    .append("元打")
                    .append(activityRule.getBenefitDiscount())
                    .append("折");
        }
        return ruleDesc.toString();
    }

    @Autowired
    private CouponInfoService couponInfoService;
    @Override
    public Map<String, Object> findActivityAndCoupon(Long skuId, Long userId) {
        //1.创建Map用来封装结果
        Map map=new HashMap();
        //2.查询该商品参加的优惠活动和活动规则
        List<ActivityRule> activityRule = this.findActivityRule(skuId);
        //3.根据商品id和用户id,查询该商品参加的优惠券
        List<CouponInfo> couponInfoList=couponInfoService.findCouponInfo(userId,skuId);
        //4.将优惠券列表和活动规则列表封装到map集合中
        map.put("activityRuleList", activityRule);
        map.put("couponInfoList", couponInfoList);
        return map;
    }
    //根据某个商品id,查询活动规则
    public  List<ActivityRule> findActivityRule(Long skuId) {
        //1.根据skuid,查询该商品的活动规则列表
            List<ActivityRule> activityRuleList= baseMapper.selectActivityRuleList(skuId);
            //2.1 判断规则列表是否有值
            if(!CollectionUtils.isEmpty(activityRuleList)){
                for (ActivityRule activityRule : activityRuleList) {
                    //将活动规则转换成字符串
                    String ruleDesc = this.getRuleDesc(activityRule);
                    activityRule.setRuleDesc(ruleDesc);
                }
        }
        return activityRuleList;
    }

    @Override  //查看购物车中商品的优惠活动和优惠券
    public OrderConfirmVo findCartActivityAndCoupon(List<CartInfo> cartInfoList, Long userId) {
        //1.获取购物车中每件商品参与的活动(参加活动+没有参加活动)
        List<CartInfoVo>  cartInfoVoList=this.findCartActivityList(cartInfoList);
        //2.根据活动规则分组，并计算参与活动之后的金额(优惠金额)
        BigDecimal activityReduceAmount =new BigDecimal("0");
        if(!CollectionUtils.isEmpty(cartInfoVoList)){
             activityReduceAmount = cartInfoVoList.stream()
                    .filter(cartInfoVo -> cartInfoVo.getActivityRule() != null)
                    .map(cartInfoVo -> cartInfoVo.getActivityRule().getReduceAmount())
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
        }
        //3.获取购物车中可以使用优惠券的列表,参数是购物车商品列表和用户id
        List<CouponInfo> couponInfoList=couponInfoService.findCartCouponInfo(cartInfoList,userId); // TODO
        //4.优惠券可以优惠的金额(一次只能使用一张优惠券)
        BigDecimal couponReduceAmount =new BigDecimal("0");
        if(!CollectionUtils.isEmpty(couponInfoList)){
             couponReduceAmount = couponInfoList.stream()
                    .filter(couponInfo -> couponInfo.getIsOptimal().intValue() == 1)//优惠券应该使用的是最优选择的那张
                    .map(couponInfo -> couponInfo.getAmount())
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
        }
        //5.购物车商品的原始总金额
        BigDecimal yuanReduceAmount = cartInfoList.stream()
                .filter(cartInfo -> cartInfo.getIsChecked().intValue() == 1)
                .map(cartInfo -> cartInfo.getCartPrice().multiply(new BigDecimal(cartInfo.getSkuNum())))
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        //6.计算最终总金额(排除参加活动的金额和使用的优惠券金额)
        BigDecimal totalAmount =
                yuanReduceAmount.subtract(couponReduceAmount).subtract(activityReduceAmount);
        //7.封装结果并返回
        OrderConfirmVo orderConfirmVo = new OrderConfirmVo();
        orderConfirmVo.setCarInfoVoList(cartInfoVoList);
        orderConfirmVo.setCouponInfoList(couponInfoList);
        orderConfirmVo.setActivityReduceAmount(activityReduceAmount);
        orderConfirmVo.setCouponReduceAmount(couponReduceAmount);
        orderConfirmVo.setOriginalTotalAmount(yuanReduceAmount);
        orderConfirmVo.setTotalAmount(totalAmount);
        return orderConfirmVo;
    }


    //获取购物车中每件商品参与的活动
    public List<CartInfoVo> findCartActivityList(List<CartInfo> cartInfoList) {
        //1.创建一个List集合，封装最后的结果数据
        List<CartInfoVo>  cartInfoVoList=new ArrayList<CartInfoVo>();
        //2.把购物车里参加相同活动的购物商品汇总到一起
        //2.1 获取购物车中商品的skuid
        List<Long> skuIdList = cartInfoList.stream().map(CartInfo::getSkuId).collect(Collectors.toList());
        //2.2 根据skuIdList,查看商品参加的活动列表-activity_sku表
        List<ActivitySku> activitySkuList=activitySkuMapper.selectCartActivityList(skuIdList);
        //2.3 根据活动id,进行分组,将结果封装到Map(key=活动id value=skuid的集合列表)
        //技术点： 使用stream流
        //Map map=Collectors.groupingBy(key,value);
        //Collectors.groupingBy(ActivitySku::getActivityId,map集合的value值) 根据活动id对activitySkuList进行分组,并作为map的key
        //map集合value值:Collectors.mapping(ActivitySku::getSkuId)   将activitySkuList中的skuid取出并分类，作为上一步map的value值
        Map<Long, Set<Long>> activityIdMapSkuId = activitySkuList.stream().collect(Collectors.groupingBy(ActivitySku::getActivityId,
                Collectors.mapping(ActivitySku::getSkuId, Collectors.toSet())));
        //3.获取活动对应的活动规则
        //3.1 先创建一个map集合，封装每个活动对应的活动规则，key=活动ID，value=活动规则
        Map<Long, List<ActivityRule>> activityIdToActivityRuleListMap = new HashMap<>();
        //3.2 先遍历activityIdMapSkuId集合，获取参加的所有活动的id
        Set<Long> activityIdSet = activityIdMapSkuId.keySet();
        //3.3 根据活动id,查询活动规则 activity_rule
        if(!CollectionUtils.isEmpty(activityIdSet)){
            LambdaQueryWrapper<ActivityRule> wrapper = new LambdaQueryWrapper<>();
            wrapper.orderByDesc(ActivityRule::getConditionAmount);//根据满减金额降序排序
            wrapper.in(ActivityRule::getActivityId,activityIdSet);
            //所有活动的活动规则
            List<ActivityRule> activityRuleList = activityRuleMapper.selectList(wrapper);
            // 3.4将所有活动的活动规则根据活动ID分组，保存到map中activityIdToActivityRuleListMap
            //如果调取groupingby()的集合正好是返回的map集合的value值，则groupingby中的第二个参数可以省略
            activityIdToActivityRuleListMap=
                    activityRuleList.stream().collect(Collectors.groupingBy(ActivityRule::getActivityId));
        }
        //4.根据活动汇总商品信息，相同活动的商品为一组，显示到页面，并计算最优惠的金额
        Set skuid_in_activity_set=new HashSet();//保存参加了活动的商品id

        //4.1 计算参加了活动的
        if(!CollectionUtils.isEmpty(activityIdMapSkuId)){
                //遍历activityIdMapSkuId集合，取出活动id和参加该活动的商品id（skuid）
            Set<Long> keySet = activityIdMapSkuId.keySet();
            for (Long activityId : keySet) {
                //得到某个活动的商品id
                Set<Long> skuidSet = activityIdMapSkuId.get(activityId);
                skuid_in_activity_set.addAll(skuidSet);
                //根据商品id,查询商品信息(单价，购买数量)
                List<CartInfo> infoList = cartInfoList.stream()
                        .filter(cartInfo -> skuidSet.contains(cartInfo.getSkuId()))
                        .collect(Collectors.toList());
                //计算活动的总金额-参加活动之前的
                BigDecimal totalAmount = this.computeTotalAmount(infoList);
                //计算活动的商品数量
                int totalCartNum = this.computeCartNum(infoList);
                //计算当前活动对应的最有规则
                //计算参加活动后的金额-要根据活动类型进行判断
                //(1) 获取活动的规则
                List<ActivityRule> activityRuleList = activityIdToActivityRuleListMap.get(activityId);
                if(CollectionUtils.isEmpty(activityRuleList)) continue;
                //(2) 获取该活动的活动类型
                ActivityType activityType = activityRuleList.get(0).getActivityType();
                //(3) 判断活动的类型,获取活动规则
                ActivityRule  activityRule=null;
                if(activityType==ActivityType.FULL_REDUCTION){//满减
                    activityRule=this.computeFullReduction(totalAmount,activityRuleList);
                }else{  //满量
                    activityRule=this.computeFullDiscount(totalCartNum,totalAmount,activityRuleList);
                }
                //(4) 封装结果数据
                CartInfoVo cartInfoVo = new CartInfoVo();
                cartInfoVo.setCartInfoList(infoList);
                cartInfoVo.setActivityRule(activityRule);
                cartInfoVoList.add(cartInfoVo);
            }

        }

        //4.2 计算没有参加活动的
        skuIdList.removeAll(skuid_in_activity_set);
        if(!CollectionUtils.isEmpty(skuIdList)){
                //获取没有参加活动的商品id,根据商品id，查看商品信息-cartInfo
            //创建一个集合，保存没有参加活动的商品列表
            /*List<CartInfo> no_activity_cartinfo=new ArrayList<>();
            for (Long skuid : skuIdList) {
                for (CartInfo cartInfo : cartInfoList) {
                    if(cartInfo.getSkuId()==skuid){
                        no_activity_cartinfo.add(cartInfo);
                    }
                }
            }
            CartInfoVo cartInfoVo = new CartInfoVo();
            cartInfoVo.setCartInfoList(no_activity_cartinfo);
            cartInfoVo.setActivityRule(null);
            cartInfoVoList.add(cartInfoVo);*/

            //获取skuId对应的购物项
            Map<Long, CartInfo> skuIdToCartInfoMap =
                    cartInfoList.stream().collect(Collectors.toMap(CartInfo::getSkuId, CartInfo->CartInfo));
            for(Long skuId : skuIdList) {
                CartInfoVo carInfoVo = new CartInfoVo();
                carInfoVo.setActivityRule(null);
                List<CartInfo> currentCartInfoList = new ArrayList<>();
                currentCartInfoList.add(skuIdToCartInfoMap.get(skuId));
                carInfoVo.setCartInfoList(currentCartInfoList);
                cartInfoVoList.add(carInfoVo);
            }
        }

        return cartInfoVoList;
    }

    /**
     * 计算满量打折最优规则
     * @param totalNum
     * @param activityRuleList //该活动规则skuActivityRuleList数据，已经按照优惠折扣从大到小排序了
     */
    private ActivityRule computeFullDiscount(Integer totalNum, BigDecimal totalAmount, List<ActivityRule> activityRuleList) {
        ActivityRule optimalActivityRule = null;
        //该活动规则skuActivityRuleList数据，已经按照优惠金额从大到小排序了
        for (ActivityRule activityRule : activityRuleList) {
            //如果订单项购买个数大于等于满减件数，则优化打折
            if (totalNum.intValue() >= activityRule.getConditionNum()) {
                BigDecimal skuDiscountTotalAmount = totalAmount.multiply(activityRule.getBenefitDiscount().divide(new BigDecimal("10")));
                BigDecimal reduceAmount = totalAmount.subtract(skuDiscountTotalAmount);
                activityRule.setReduceAmount(reduceAmount);
                optimalActivityRule = activityRule;
                break;
            }
        }
        if(null == optimalActivityRule) {
            //如果没有满足条件的取最小满足条件的一项
            optimalActivityRule = activityRuleList.get(activityRuleList.size()-1);
            optimalActivityRule.setReduceAmount(new BigDecimal("0"));
            optimalActivityRule.setSelectType(1);

            StringBuffer ruleDesc = new StringBuffer()
                    .append("满")
                    .append(optimalActivityRule.getConditionNum())
                    .append("元打")
                    .append(optimalActivityRule.getBenefitDiscount())
                    .append("折，还差")
                    .append(totalNum-optimalActivityRule.getConditionNum())
                    .append("件");
            optimalActivityRule.setRuleDesc(ruleDesc.toString());
        } else {
            StringBuffer ruleDesc = new StringBuffer()
                    .append("满")
                    .append(optimalActivityRule.getConditionNum())
                    .append("元打")
                    .append(optimalActivityRule.getBenefitDiscount())
                    .append("折，已减")
                    .append(optimalActivityRule.getReduceAmount())
                    .append("元");
            optimalActivityRule.setRuleDesc(ruleDesc.toString());
            optimalActivityRule.setSelectType(2);
        }
        return optimalActivityRule;
    }

    /**
     * 计算满减最优规则
     * @param totalAmount
     * @param activityRuleList //该活动规则skuActivityRuleList数据，已经按照优惠金额从大到小排序了
     */
    private ActivityRule computeFullReduction(BigDecimal totalAmount, List<ActivityRule> activityRuleList) {
        ActivityRule optimalActivityRule = null;
        //该活动规则skuActivityRuleList数据，已经按照优惠金额从大到小排序了
        for (ActivityRule activityRule : activityRuleList) {
            //如果订单项金额大于等于满减金额，则优惠金额
            if (totalAmount.compareTo(activityRule.getConditionAmount()) > -1) {
                //优惠后减少金额
                activityRule.setReduceAmount(activityRule.getBenefitAmount());
                optimalActivityRule = activityRule;
                break;
            }
        }
        if(null == optimalActivityRule) {
            //如果没有满足条件的取最小满足条件的一项
            optimalActivityRule = activityRuleList.get(activityRuleList.size()-1);
            optimalActivityRule.setReduceAmount(new BigDecimal("0"));
            optimalActivityRule.setSelectType(1);

            StringBuffer ruleDesc = new StringBuffer()
                    .append("满")
                    .append(optimalActivityRule.getConditionAmount())
                    .append("元减")
                    .append(optimalActivityRule.getBenefitAmount())
                    .append("元，还差")
                    .append(totalAmount.subtract(optimalActivityRule.getConditionAmount()))
                    .append("元");
            optimalActivityRule.setRuleDesc(ruleDesc.toString());
        } else {
            StringBuffer ruleDesc = new StringBuffer()
                    .append("满")
                    .append(optimalActivityRule.getConditionAmount())
                    .append("元减")
                    .append(optimalActivityRule.getBenefitAmount())
                    .append("元，已减")
                    .append(optimalActivityRule.getReduceAmount())
                    .append("元");
            optimalActivityRule.setRuleDesc(ruleDesc.toString());
            optimalActivityRule.setSelectType(2);
        }
        return optimalActivityRule;
    }


    //  计算总金额
    private BigDecimal computeTotalAmount(List<CartInfo> cartInfoList) {
        BigDecimal total = new BigDecimal("0");
        for (CartInfo cartInfo : cartInfoList) {
            //是否选中
            if(cartInfo.getIsChecked().intValue() == 1) {
                BigDecimal itemTotal = cartInfo.getCartPrice().multiply(new BigDecimal(cartInfo.getSkuNum()));
                total = total.add(itemTotal);
            }
        }
        return total;
    }
    //计算总数量
    private int computeCartNum(List<CartInfo> cartInfoList) {
        int total = 0;
        for (CartInfo cartInfo : cartInfoList) {
            //是否选中
            if(cartInfo.getIsChecked().intValue() == 1) {
                total += cartInfo.getSkuNum();
            }
        }
        return total;
    }
}
